
#include "GarbageObject.h"
#include "GarbageManager.h"

static GarbageManager* CacheGCManager_ = nullptr;

GarbageObject::GarbageObject()
{
}

GarbageObject::~GarbageObject()
{
}

void GarbageObject::Release(GarbageObject* target)
{
	if(target == nullptr)
	{
		CacheGCManager_->Release(this);
	}else
	{
		if(this->isGarbage_)
			return;

		auto it = this->refTable_.find(target);
		if(it != this->refTable_.end())
		{
			it->second = it->second - 1;
			
			if(it->second <= 0)
				this->refTable_.erase(it);
		}

		this->isGarbage_ = (!CacheGCManager_->CheckHasRef(this) && this->refTable_.empty());
		if(this->isGarbage_ && this != CacheGCManager_)
		{
			this->isGarbage_ = true;
			CacheGCManager_->Push(this);
		}
	}
}

void GarbageObject::Retain(GarbageObject* target)
{
	if(target == nullptr)
	{
		CacheGCManager_->Retain(this);
	}else
	{
		if(this->isGarbage_)
			return;

		auto it = this->refTable_.find(target);
		if(it != this->refTable_.end())
			it->second = it->second + 1;
		else
			this->refTable_[target] = 1;
	}
}

void GarbageObject::OnNewObject(GarbageObject* obj)
{
	if(CacheGCManager_ == nullptr)
		CacheGCManager_ = Inst(GarbageManager);
	CacheGCManager_->onNewObj(obj);
}

void GarbageObject::OnDeleteObject(GarbageObject* obj)
{
	CacheGCManager_->onRemoveObj(obj);
}

bool GarbageObject::CheckHasRef(GarbageObject* obj)
{
	auto it = this->refTable_.find(obj);
	return (it == this->refTable_.end());
}

void GarbageObject::DoMark()
{
	if(this->isGarbage_ || this->gcCheckMark_)
		return;

	this->gcCheckMark_ = true;
	for(auto& it : this->refTable_)
		it.first->DoMark();
}
